/*
* @file    :task.c
* @module  :TASK
* @author  :LingFengLu
* @date    :2023-06-08
*/
#include "devos.h"
#include "task.h"
#include "task_system.h"
#include "task_comm.h"
#include "task_shell.h"
#include "task_glucose.h"
#include "task_monitor.h"
#include "drv.h"
//Constant definition    宏定义
#define TASK_PRIORITY_SYSTEM			0
#define TASK_PRIORITY_COMM				4
#define TASK_PRIORITY_SHELL				3
#define TASK_PRIORITY_GLUCOSE			1
#define TASK_PRIORITY_MONITOR			2
#define TASK_PRIORITY_IDLE				5






//Type definition    类型定义
typedef enum
{
	TASK_ID_SYSTEM = 0,
	TASK_ID_COMM,
	TASK_ID_SHELL,
	TASK_ID_GLUCOSE,
	TASK_ID_MONITOR,
	TASK_ID_IDLE,
	TASK_COUNT_ID
} task_id;

typedef uint (*task_set_config)
(
uint ui_Parameter,
const uint8 *u8p_Value,
uint ui_Length
);

typedef uint (*task_get_config)
(
uint ui_Parameter,
uint8 *u8p_Value,
uint *uip_Length
);
//Global variable definition    全局变量定义

//Private function declaration   私有函数申明

static void Task_ProcessIdle
(
devos_task_handle t_TaskHandle
);
static uint Task_CheckIdle(void);
static void Task_TriggerTick(void *a);
static void Task_TriggerClock(void *a);

//Private variable definition    私有变量定义

static uint m_ui_MessageID = {0};
static devos_task_handle m_t_TaskHandle[TASK_COUNT_ID] = {0};
static uint16 m_u16_MessageData[TASK_COUNT_MESSAGE_ID] = {0};

static const task_set_config m_fp_SetConfig[TASK_COUNT_PORT] =
{
	TaskSystem_SetConfig,
	TaskComm_SetConfig,
	TaskShell_SetConfig,
	TaskGlucose_SetConfig,
	0,
	TaskMonitor_SetConfig
};
static const task_get_config m_fp_GetConfig[TASK_COUNT_PORT] =
{
	TaskSystem_GetConfig,
	TaskComm_GetConfig,
	TaskShell_GetConfig,
	TaskGlucose_GetConfig,
	0,
	TaskMonitor_GetConfig
};

static const devos_task_profile m_t_TaskProfile[TASK_COUNT_ID] =
{
	{
		TASK_PRIORITY_SYSTEM,
		TaskSystem_Process
	},
	{
		TASK_PRIORITY_COMM,
		TaskComm_Process
	},
	{
		TASK_PRIORITY_SHELL,
		TaskShell_Process
	},
	{
		TASK_PRIORITY_GLUCOSE,
		TaskGlucose_Process
	},
	{
		TASK_PRIORITY_MONITOR,
		TaskMonitor_Process
	},
	{
		TASK_PRIORITY_IDLE,
		Task_ProcessIdle
	}
};








//Public function definition   公共函数定义
void Task_Init(void)
{
	
	m_ui_MessageID = TASK_COUNT_MESSAGE_ID;
	
	DevOS_Initialize(Task_EnterCritical, Task_ExitCritical);
	
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_SYSTEM], 
			 &m_t_TaskProfile[TASK_ID_SYSTEM]);
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_COMM], 
			 &m_t_TaskProfile[TASK_ID_COMM]);
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_SHELL], 
			 &m_t_TaskProfile[TASK_ID_SHELL]);
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_GLUCOSE], 
			 &m_t_TaskProfile[TASK_ID_GLUCOSE]);
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_MONITOR], 
			 &m_t_TaskProfile[TASK_ID_MONITOR]);
	DevOS_TaskCreate(&m_t_TaskHandle[TASK_ID_IDLE], 
			 &m_t_TaskProfile[TASK_ID_IDLE]);
	
	
	DevOS_MessageInitialize(TASK_MESSAGE_ID_CLOCK, 
	(uint8 *)&m_u16_MessageData[TASK_MESSAGE_ID_CLOCK], 
	sizeof(m_u16_MessageData[TASK_MESSAGE_ID_CLOCK]));
	DevOS_MessageInitialize(TASK_MESSAGE_ID_TICK, 
	(uint8 *)&m_u16_MessageData[TASK_MESSAGE_ID_TICK], 
	sizeof(m_u16_MessageData[TASK_MESSAGE_ID_TICK]));
	
	DevOS_MessageRegister(TASK_MESSAGE_ID_CLOCK, 
			      m_t_TaskHandle[TASK_ID_SYSTEM]);
	DevOS_MessageRegister(TASK_MESSAGE_ID_CLOCK, 
			      m_t_TaskHandle[TASK_ID_SHELL]);
	DevOS_MessageRegister(TASK_MESSAGE_ID_CLOCK, 
			      m_t_TaskHandle[TASK_ID_MONITOR]);
	DevOS_MessageRegister(TASK_MESSAGE_ID_CLOCK, 
			      m_t_TaskHandle[TASK_ID_GLUCOSE]);

	DevOS_MessageRegister(TASK_MESSAGE_ID_TICK, 
			      m_t_TaskHandle[TASK_ID_COMM]);
	
	TaskSystem_Init(m_t_TaskHandle[TASK_ID_SYSTEM]);
	TaskComm_Init(m_t_TaskHandle[TASK_ID_COMM]);
	TaskMonitor_Init(m_t_TaskHandle[TASK_ID_MONITOR]);
	TaskShell_Init(m_t_TaskHandle[TASK_ID_SHELL]);
	TaskGlucose_Init(m_t_TaskHandle[TASK_ID_GLUCOSE]);
	DrvTimer_Start(DRV_TIMER_ID0 ,TICK_PERIOD ,0 ,Task_TriggerTick) ;
	DrvTimer_Start(DRV_TIMER_ID1 ,CLOCK_PERIOD ,1 ,Task_TriggerClock) ;
}




void Task_Process(void)
{
	uint8 u8_Value;
	PowerSaveLevels stopLevel;

	while (1)
	{
		
		Drv_SystemPorcessAction();
		Drv_GetConfig(DRV_PARAM_WORK_STATE, &u8_Value, (uint *)0);
//		Drv_Sleep(&stopLevel) ;
		if (u8_Value == DRV_WORK_STATE_WAIT)
		{
			  DevOS_Schedule();
		}
		else
		{
//			DrvUnGpio_Init();
		}
	}
	
}

uint Task_ObtainMessageID
(
uint *uip_MessageID
)
{
	if (m_ui_MessageID >= DEVOS_MESSAGE_COUNT_MAX)
	{
		return FUNCTION_FAIL;
	}
	
	*uip_MessageID = m_ui_MessageID;
	m_ui_MessageID++;
	
	return FUNCTION_OK;
}

uint Task_HandleCommand
( 
uint8 u8_SourcePort,
uint8 u8_TargetPort,
message_command *tp_Command
)
{
	uint ui_Length;
	uint ui_Acknowledge;
	uint8 u8_Port;
	
	if (MESSAGE_GET_MAJOR_PORT(u8_TargetPort) != MESSAGE_PORT_TASK)
		return FUNCTION_FAIL;
	
	u8_Port = MESSAGE_GET_MINOR_PORT(u8_TargetPort);
	
	if (u8_Port >= TASK_COUNT_PORT)
		return FUNCTION_FAIL;
	
	ui_Acknowledge = FUNCTION_FAIL;
	ui_Length = (uint)tp_Command->u8_Length;
	
	switch (tp_Command->u8_Operation) {
	    case MESSAGE_OPERATION_PAIR:
		if (u8_Port != TASK_PORT_COMM)
			return FUNCTION_FAIL;
		ui_Acknowledge = TaskComm_Pair( (uint)tp_Command->u8_Parameter,
					       tp_Command->u8p_Data,
					       &ui_Length );
		LOG_INFO("ui_Acknowledge:%d",ui_Acknowledge);
		tp_Command->u8p_Data[0] = (uint8)ui_Acknowledge;
		tp_Command->u8_Operation = MESSAGE_OPERATION_PAIR;
		tp_Command->u8_Length = (uint8)ui_Length;
		break;
		
	    case MESSAGE_OPERATION_UNPAIR:
		if (u8_Port != TASK_PORT_COMM)
			return FUNCTION_FAIL;
		ui_Acknowledge = TaskComm_Unpair( (uint)tp_Command->u8_Parameter,
						 tp_Command->u8p_Data,
						 &ui_Length );
		tp_Command->u8p_Data[0] = (uint8)ui_Acknowledge;
		tp_Command->u8_Operation = MESSAGE_OPERATION_UNPAIR;
		tp_Command->u8_Length = sizeof(tp_Command->u8p_Data[0]);
		break;
		
	    case MESSAGE_OPERATION_BOND:
		if (u8_Port != TASK_PORT_COMM)
			return FUNCTION_FAIL;
		ui_Acknowledge = TaskComm_Bond( (uint)tp_Command->u8_Parameter,
					       tp_Command->u8p_Data,
					       &ui_Length );
		LOG_INFO("ui_Acknowledge:%d",ui_Acknowledge);
		//	    tp_Command->u8p_Data[0] = (uint8)ui_Acknowledge;
		tp_Command->u8_Operation = MESSAGE_OPERATION_BOND;
		tp_Command->u8_Length = ui_Length;
		break;
		
	    case MESSAGE_OPERATION_SET:
		if (m_fp_SetConfig[u8_Port] != (task_set_config)0)
		{
			ui_Acknowledge = m_fp_SetConfig[u8_Port]( (uint)tp_Command->u8_Parameter,
								 tp_Command->u8p_Data,
								 ui_Length );
			tp_Command->u8p_Data[0] = (uint8)ui_Acknowledge;
			tp_Command->u8_Operation = MESSAGE_OPERATION_ACKNOWLEDGE;
			tp_Command->u8_Length = sizeof(tp_Command->u8p_Data[0]);
		}
		break;
		
	    case MESSAGE_OPERATION_GET:
		if (m_fp_GetConfig[u8_Port] != (task_get_config)0)
		{
			LOG_INFO("MESSAGE_OPERATION_GET:u8_Port:%d u8_Parameter:%d",u8_Port,tp_Command->u8_Parameter);
			ui_Acknowledge = m_fp_GetConfig[u8_Port]( (uint)tp_Command->u8_Parameter,
								 tp_Command->u8p_Data,
								 &ui_Length );
			if (ui_Acknowledge != FUNCTION_OK)
				return FUNCTION_FAIL;
			tp_Command->u8_Operation = MESSAGE_OPERATION_NOTIFY;
			tp_Command->u8_Length = (uint8)ui_Length;
		}
		break;
		
	    case MESSAGE_OPERATION_NOTIFY:
	    case MESSAGE_OPERATION_ACKNOWLEDGE:
		tp_Command->u8p_Data[0] = (uint8)MESSAGE_EVENT_ACKNOWLEDGE;
		tp_Command->u8_Operation = MESSAGE_OPERATION_EVENT;
		tp_Command->u8_Length = sizeof(tp_Command->u8p_Data[0]);
		break;
		
	    default:
		return FUNCTION_FAIL;
	}
	
	return FUNCTION_OK;
}



uint Task_SendMessage
(
uint ui_MessageID,
const uint8 *u8p_Data,
uint ui_Length
)
{
	uint8 u8_Value;

	if (Drv_GetConfig(DRV_PARAM_WORK_STATE, &u8_Value, (uint *)0) != FUNCTION_OK)
	{
		return FUNCTION_FAIL;
	}
	if (u8_Value == DRV_WORK_STATE_FINISH)
	{
		Task_EnterCritical();
		u8_Value = DRV_WORK_STATE_WAIT;
		Drv_SetConfig(DRV_PARAM_WORK_STATE, &u8_Value, 
			sizeof(u8_Value));	
//		DrvTimer_Start(DRV_TIMER_ID0 ,TICK_PERIOD ,0 ,Task_TriggerTick) ;
		Task_ExitCritical();
	}
	return DevOS_MessageSend((devos_int)ui_MessageID, u8p_Data, 
				 (devos_int)ui_Length);
}

void Task_EnterCritical(void)
{
	Drv_DisableInterrupt();
}

void Task_ExitCritical(void)
{
	Drv_EnableInterrupt();
}






//Private function definition   私有函数定义

static void Task_ProcessIdle
(
devos_task_handle t_TaskHandle
)
{
  	// static uint8 u8_SleepMode;
	static uint8 u8_Value;
	DEVOS_TASK_BEGIN
	// LOG_INFO("Task_ProcessIdle");
	if(Task_CheckIdle() == FUNCTION_OK)//check Idle
	{
		Drv_GetConfig(DRV_PARAM_WORK_STATE,&u8_Value,
					0);
		if(u8_Value ==  DRV_WORK_STATE_WAIT)
		{
			u8_Value = DRV_WORK_STATE_FINISH;
			Drv_SetConfig(DRV_PARAM_WORK_STATE, &u8_Value,
						sizeof(u8_Value));
		}
	}

    DEVOS_TASK_END
}
static uint Task_CheckIdle(void)
{
	uint8 u8_Value = 0;
	if( TaskComm_GetConfig(TASK_COMM_PARAM_BUSY,&u8_Value,0) != FUNCTION_OK)
		return FUNCTION_FAIL;
	if(u8_Value != 0)
		return FUNCTION_FAIL;
	
	if( TaskGlucose_GetConfig(TASK_GLUCOSE_PARAM_BUSY,&u8_Value,0) != FUNCTION_OK)
		return FUNCTION_FAIL;
	if(u8_Value != 0)
		return FUNCTION_FAIL;
	
	if( TaskMonitor_GetConfig(TASK_MONITOR_PARAM_BUSY,&u8_Value,0) != FUNCTION_OK)
		return FUNCTION_FAIL;
	if(u8_Value != 0)
		return FUNCTION_FAIL;
	
	if( TaskShell_GetConfig(TASK_SHELL_PARAM_BUSY,&u8_Value,0) != FUNCTION_OK)
		return FUNCTION_FAIL;
	if(u8_Value != 0)
		return FUNCTION_FAIL;
	
	if( TaskSystem_GetConfig(TASK_SYSTEM_PARAM_BUSY,&u8_Value,0) != FUNCTION_OK)
		return FUNCTION_FAIL;
	if(u8_Value != 0)
		return FUNCTION_FAIL;
	
	return FUNCTION_OK;
}
static void Task_TriggerTick(void *a)
{
	uint16 u16_TickTime = TICK_PERIOD;
	DevOS_Tick(u16_TickTime);
    DevOS_MessageSend( TASK_MESSAGE_ID_TICK,
                        (const uint8 *)&u16_TickTime,
                        sizeof(u16_TickTime) );

	uint8 u8_Value = DRV_WORK_STATE_FINISH;
	Drv_GetConfig(DRV_PARAM_WORK_STATE,&u8_Value,
				0);
	if(u8_Value ==  DRV_WORK_STATE_WAIT)
	{
		uint8 u8_Value = 1;
		DrvTimer_SetConfig(DRV_TIMER_ID0,DRV_TIMER_PARAM_SWITCH,
				   (uint8 *)&u8_Value,
				   sizeof(u8_Value)); 
	}
	u8_Value = 1 ;
	DrvTimer_SetConfig(DRV_TIMER_ID0 ,DRV_TIMER_PARAM_TIMEOUTFLAG ,&u8_Value ,0) ;
}

static void Task_TriggerClock(void *a)
{
	uint16 u16_TickTime = CLOCK_PERIOD;
	Task_SendMessage(TASK_MESSAGE_ID_CLOCK, (const uint8 *)&u16_TickTime, 
			 sizeof(u16_TickTime));
	uint8 u8_Value = 1 ;
	DrvTimer_SetConfig(DRV_TIMER_ID1 ,DRV_TIMER_PARAM_TIMEOUTFLAG ,&u8_Value ,0) ;
}

